/* Copyright (C) 
 * 
 * Disclaim
 * This program is the property of AI Speech Ltd. It shall be communicated to
 * authorized personnel only. It is not to be disclosed outside the group without
 * prior written consent. If you are not sure if you’re authorized to read this
 * program, please contact info@aispeech.com before reading.
 * 
 */

/**
 * @file wtk_utils_str_iter.h
 * 
 * @brief an iterator to in-place visit sub-element of string
 * 
 * @author wxm71(weixing.mei@aispeech.com)
 * 
 * @version 0.0.1
 * 
 * @date 2014-12-03
 */

#ifndef ___WXM71___AISPEECH_WTK_UTILS_STR_ITER__HEADER___
#define ___WXM71___AISPEECH_WTK_UTILS_STR_ITER__HEADER___

#include "wtk/core/wtk_str.h"
#include "wtk/core/wtk_array.h"


#ifdef __cplusplus 
extern "C" {
#endif 

typedef struct wtk_str_iter wtk_str_iter_t;
typedef wtk_string_t(*wtk_str_iter_next_handler_t)(wtk_str_iter_t*);


/**
 * @brief an iterator used to iterate string's sub-element in place
 *
 * @note either change of raw string or seperator string will make all iterator invalid, 
 * so, make RAW STRING AND SEPERATOR UNCHANGED during the life time of created iterator
 */
struct wtk_str_iter {
    char *data;             ///< raw string which this iterator belongs to
    char *dataEnd;          ///< pointer to the last character of original string

    char *ptr;              ///< current position in raw string

    // seperator used to split string  
    union {
        char c;             ///< character used to split
        wtk_string_t str;   ///< string or character set used to split 
        wtk_array_t *arr;   ///< string set used to split
    } sep;

    wtk_str_iter_next_handler_t hand;
};


/**
 * @brief get next sub-element
 */
#define wtk_str_iter_next(iter) ((iter)->hand(iter))


/**
 * @brief return the number of element left in iterator sequence 
 *
 * @note this function will change the current position of iterator, if wanna to reuse
 * this iterator, call wtk_str_iter_reset first
 */
int wtk_str_iter_cnt(wtk_str_iter_t *iter);



/**
 * @brief move the iterator to position before first sub-element, that's, the next
 * call wtk_str_iter_next will get the first sub-element
 */
#define wtk_str_iter_reset(iter) ((iter)->ptr = (iter)->data)


/**
 * @brief create an iterator to in-place visit sub-str-chunk split by given seperator character
 * 
 * @param sp seperator used to split raw string
 *
 * @note for example: 
 * - GIVEN 
 *   data = "this|is|a|test", len=strlen(data), sep='|'
 *
 * - THEN 
 *   result iterator is able to visit "this", "is", "a", "test" sequently
 *
 * - TIPS
 *   iterator will be invalid once raw string have changed
 */
wtk_str_iter_t wtk_char_split_iter(char *data, int len, char sep);
#define wtk_char_split_iter_s(s, sep) wtk_char_split_iter(s, strlen(s), sep)
#define wtk_char_split_iter_str(str, sep) wtk_char_split_iter((str)->data, (str)->len, sep)


/**
 * @brief create an iterator to visit sub-str-chunk split by a set of seperator character
 * 
 * @param sp seperator used to split raw string
 *
 * @note for example: 
 * - GIVEN 
 *   data = "this|is+a=test", len=strlen(data), sep="|=+"
 *
 * - THEN 
 *   result iterator is able to visit "this", "is", "a", "test" sequently
 *
 * - TIPS
 *   iterator will be invalid once raw string have changed
 */
wtk_str_iter_t wtk_cset_split_iter(char *data, int len, char *sep, int snum);
#define wtk_cset_split_iter_s(s, sep, snum) wtk_cset_split_iter(s, strlen(s), sep, snum)
#define wtk_cset_split_iter_str(str, sep, snum) wtk_cset_split_iter((str)->data, (str)->len, sep, snum)


/**
 * @brief same as wtk_char_split_iter, but split raw string with a given seperator string
 *
 * @note iterator will be invalid either raw string or seperator string have changed
 */
wtk_str_iter_t wtk_str_split_iter(char *data, int len, char *sep, int slen);


/**
 * @brief same as wtk_str_split_iter, but seperator are a set of string
 *
 * @param arr the seperator string set, an array of wtk_string_t*
 */
wtk_str_iter_t wtk_sset_split_iter(char *data, int len, wtk_array_t *arr);
#define wtk_sset_split_iter_s(s, arr) wtk_sset_split_iter(s, strlen(s), arr)
#define wtk_sset_split_iter_str(str, arr) wtk_sset_split_iter((str)->data, (str)->len, arr)


/**
 * @brief create iterator used to iterate each word in raw string
 *
 * "word", define as a sequence of characters which exclude those reject by isspace
 */
wtk_str_iter_t wtk_wrd_iter(char *data, int len);
#define wtk_wrd_iter_s(s) wtk_wrd_iter(s, strlen(s))
#define wtk_wrd_iter_str(str) wtk_wrd_iter((str)->data, (str)->len)


/**
 * @brief create iterator used to iterator each utf-8 word in raw string
 */
wtk_str_iter_t wtk_utf8_iter(char *data, int len);
#define wtk_utf8_iter_s(s) wtk_utf8_iter(s, strlen(s))
#define wtk_utf8_iter_str(str) wtk_utf8_iter((str)->data, (str)->len)


#ifdef __cplusplus  
};
#endif

#endif
